﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */
#ifndef QCARRAY_H
#define QCARRAY_H

#include <windows.h>
#include <QVector>

#define ARR_UNREF_PARAM(P) UNREFERENCED_PARAMETER(P)

template <class TYPE, class ARG_TYPE = const TYPE &> class QCArray {
public:
    // Construction
    QCArray();
    ~QCArray();

    BOOL IsEmpty() const;
    INT_PTR GetSize() const;
    INT_PTR GetCount() const;
    INT_PTR GetUpperBound() const;
    void SetSize(INT_PTR nNewSize, INT_PTR nGrowBy = -1);

    // Operations
    // Clean up
    void RemoveAll();

    // Accessing elements
    const TYPE &GetAt(INT_PTR nIndex) const;
    TYPE &GetAt(INT_PTR nIndex);
    void SetAt(INT_PTR nIndex, ARG_TYPE newElement);
    const TYPE &ElementAt(INT_PTR nIndex) const;
    TYPE &ElementAt(INT_PTR nIndex);

    // Direct Access to the element data (may return nullptr)
    const TYPE *GetData() const;
    TYPE *GetData();

    INT_PTR Add(ARG_TYPE newElement);
    INT_PTR Append(const QCArray &src);
    void Copy(const QCArray &src);

    // overloaded operator helpers
    const TYPE &operator[](INT_PTR nIndex) const;
    TYPE &operator[](INT_PTR nIndex);

    // Operations that move elements around
    void InsertAt(INT_PTR nIndex, ARG_TYPE newElement, INT_PTR nCount = 1);
    void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1);
    void InsertAt(INT_PTR nStartIndex, QCArray &newArray);

    // Implementation
protected:
    QVector<TYPE> list;
};

template <class TYPE, class ARG_TYPE> QCArray<TYPE, ARG_TYPE>::QCArray() {}

template <class TYPE, class ARG_TYPE> QCArray<TYPE, ARG_TYPE>::~QCArray() {}

// Attributes
template <class TYPE, class ARG_TYPE> INT_PTR QCArray<TYPE, ARG_TYPE>::GetSize() const
{
    return list.size();
}

template <class TYPE, class ARG_TYPE> INT_PTR QCArray<TYPE, ARG_TYPE>::GetCount() const
{
    return list.size();
}
template <class TYPE, class ARG_TYPE> BOOL QCArray<TYPE, ARG_TYPE>::IsEmpty() const
{
    return list.isEmpty();
}

template <class TYPE, class ARG_TYPE> INT_PTR QCArray<TYPE, ARG_TYPE>::GetUpperBound() const
{
    return list.size() - 1;
}

template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::SetSize(INT_PTR nNewSize, INT_PTR nGrowBy)
{
    ARR_UNREF_PARAM(nGrowBy);
    list.resize(static_cast<int>(nNewSize));
}

// Operations
// Clean up
template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::RemoveAll()
{
    list.clear();
}

// Accessing elements
template <class TYPE, class ARG_TYPE> const TYPE &QCArray<TYPE, ARG_TYPE>::GetAt(INT_PTR nIndex) const
{
    return list.at(static_cast<int>(nIndex));
}

template <class TYPE, class ARG_TYPE> TYPE &QCArray<TYPE, ARG_TYPE>::GetAt(INT_PTR nIndex)
{
    return const_cast<TYPE &>(list.at(static_cast<int>(nIndex)));
}

template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::SetAt(INT_PTR nIndex, ARG_TYPE newElement)
{
    if (nIndex >= list.size()) {
        SetSize(nIndex + 1, -1);
    }
    list[nIndex] = newElement;
}

template <class TYPE, class ARG_TYPE> const TYPE &QCArray<TYPE, ARG_TYPE>::ElementAt(INT_PTR nIndex) const
{
    return list[nIndex];
}

template <class TYPE, class ARG_TYPE> TYPE &QCArray<TYPE, ARG_TYPE>::ElementAt(INT_PTR nIndex)
{
    return list[nIndex];
}

// Direct Access to the element data (may return nullptr)
template <class TYPE, class ARG_TYPE> const TYPE *QCArray<TYPE, ARG_TYPE>::GetData() const
{
    return list.constData();
}

template <class TYPE, class ARG_TYPE> TYPE *QCArray<TYPE, ARG_TYPE>::GetData()
{
    return list.data();
}

template <class TYPE, class ARG_TYPE> INT_PTR QCArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
{
    list.push_back(newElement);
    return list.size() - 1;
}

template <class TYPE, class ARG_TYPE> INT_PTR QCArray<TYPE, ARG_TYPE>::Append(const QCArray &src)
{
    INT_PTR nRet = list.size();
    list.append(src.list);
    return nRet;
}

template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::Copy(const QCArray &src)
{
    list.clear();
    list.append(src.list);
}

// overloaded operator helpers
template <class TYPE, class ARG_TYPE> const TYPE &QCArray<TYPE, ARG_TYPE>::operator[](INT_PTR nIndex) const
{
    return list[static_cast<int>(nIndex)];
}

template <class TYPE, class ARG_TYPE> TYPE &QCArray<TYPE, ARG_TYPE>::operator[](INT_PTR nIndex)
{
    return list[static_cast<int>(nIndex)];
}

// Operations that move elements around
template <class TYPE, class ARG_TYPE>
void QCArray<TYPE, ARG_TYPE>::InsertAt(INT_PTR nIndex, ARG_TYPE newElement, INT_PTR nCount)
{
    list.insert(nIndex, nCount, newElement);
}

template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::RemoveAt(INT_PTR nIndex, INT_PTR nCount)
{
    list.remove(static_cast<int>(nIndex), static_cast<int>(nCount));
}

template <class TYPE, class ARG_TYPE> void QCArray<TYPE, ARG_TYPE>::InsertAt(INT_PTR nStartIndex, QCArray &newArray)
{
    QVector<TYPE> temp;
    while (nStartIndex < list.size()) {
        temp.push_front(list[list.size() - 1]);
        list.pop_back();
    }
    list.append(newArray->list);
    list.append(temp);
}

using DwordArray = QCArray<DWORD, const DWORD &>;
using WordArray = QCArray<WORD, const WORD &>;

#endif // __QCARRAY_H__
